<?php
/*
 * [JINYUN!] (C)2001-2099 Jinyunweb.com
 * This is NOT a freeware, use is subject to license terms
 
 * 发起 jsapi 支付接口	jsapi_pay
 * 发起 native 支付接口	native_pay
 * 发起 wxapp 支付接口	wxapp_pay
 * 发起 h5 支付接口		h5_pay
 * 发起 app 支付接口	app_pay
 * 发起 付款码 支付接口	micropay
 * 微信支付统一下单接口 create_order
 * 企业付款接口			mch_pay
 * 现金红包接口			redpack
 * 裂变红包接口			grouppack
*/
namespace core;
defined('BY_JYA') or exit('error');
class wechat_pay{
	/*
		初始化接口参数
		如未传入接口参数，则自动从系统支付参数中获取
		
		参数介绍
		$config=array(
			'appid'=>'商户appid',
			'mch_id'=>'商户号',
			'sub_pay'=>'是否服务商支付',
			'sub_mch_id'=>'子商户号',
			'sub_appid'=>'子商户appid',
			'key'=>'商户支付密钥',
			'apiclient_cert'=>'证书cert文件绝对路径',
			'apiclient_key'=>'证书key文件绝对路径',
		);
	*/
	public function __construct($config=array()){
		if($config){
			$this->config=$config;
		}else{
			$setting=uni_setting('pay');
			if($_SESSION['auth_wxid']){
				$auth_appid=pdo_getcolumn('core_account_wechat',array('id'=>$_SESSION['auth_wxid']),'appid');
			}
			$this->config=array(
				'appid'=>$auth_appid?:$setting['wechat_appid'],
				'mch_id'=>$setting['wechat_mchid'],
				'sub_pay'=>$setting['wechat_type'],
				'sub_mch_id'=>$setting['wechat_sub_mchid'],
				'sub_appid'=>$setting['wechat_sub_appid'],
				'key'=>$setting['wechat_miyue'],
				'v3key'=>$setting['wechat_miyuev3'],
				'serial_no'=>$setting['wechat_serial_no'],
				'payserial_no'=>$setting['wechatpay_serial_no'],
				'apiclient_cert'=>ROOT_AT."certs/{$_SESSION['uniacid']}/{$setting['wechat_mchid']}_cert.pem",
				'apiclient_key'=>ROOT_AT."certs/{$_SESSION['uniacid']}/{$setting['wechat_mchid']}_key.pem",
				'paypublic_key'=>ROOT_AT."certs/{$_SESSION['uniacid']}/{$setting['wechat_mchid']}_paypublic_key.pem",
				'payprivate_key'=>ROOT_AT."certs/{$_SESSION['uniacid']}/{$setting['wechat_mchid']}_payprivate_key.pem",
			);
		}
	}
	/*
		jsapi 支付，返回用于发起支付的数组
		参数介绍见 create_order 函数
	*/
	public function jsapi_pay($params){
		$res=$this->create_order($params,'JSAPI');
		$package=array(
			'appId'=>$this->config['appid'],
			'timeStamp'=>"".TIMESTAMP,
			'package'=>'prepay_id='.$res['prepay_id'],
			'signType'=>'MD5',
			'nonceStr'=>random(8),
		);
		$package['paySign']=$this->md5_sign($package);
		return $package;
	}
	/*
		小程序 支付，返回用于发起支付的数组
		参数介绍见 create_order 函数
	*/
	public function wxapp_pay($params){
		if($_SESSION['fromh5wxapp']==1 && $_SESSION['wxappopenid']){
			$params['openid']=$_SESSION['wxappopenid'];
		}
		$res=$this->create_order($params,'JSAPI');
		$params['wxappid']=$params['wxappid']?:$params['appid'];
		$package=array(
			'appId'=>$this->config['sub_appid']?:$this->config['appid'],
			'timeStamp'=>"".TIMESTAMP,
			'package'=>'prepay_id='.$res['prepay_id'],
			'nonceStr'=>random(32),
			'signType'=>'MD5',
		);
		$package['paySign']=$this->md5_sign($package);
		$package['success_url']=$params['success_url'];
		$package['error_url']=$params['error_url'];
		return $package;
	}
	/*
		NATIVE 支付，返回用于生成支付二维码的URL
		参数介绍见 create_order 函数
	*/
	public function native_pay($params){
		$res=$this->create_order($params,'NATIVE');
		return $res['code_url'];
	}
	/*
		H5 支付，返回用于唤起微信支付的URL
		参数介绍见 create_order 函数
	*/
	public function h5_pay($params){
		if(is_numeric($params)){
			$params=pdo_get('core_paylog',array('id'=>$params),array('title','tid','fee','jianfee'));
			if($params['jianfee']>0){
				$params['fee']=$params['fee']-$params['jianfee'];
			}
		}
		$res=$this->create_order($params,'MWEB');
		return $res['mweb_url'];
	}
	/*
		APP 支付，返回用于APP端发起支付的数组
		参数介绍见 create_order 函数
	*/
	public function app_pay($params){
		$res=$this->create_order($params,'APP');
		$package=array(
			'appid'=>$params['appid']?:$this->config['appid'],
			'partnerid'=>$this->config['mch_id'],
			'prepayid'=>$res['prepay_id'],
			'package'=>'Sign=WXPay',
			'nonceStr'=>random(32),
			'timestamp'=>"".TIMESTAMP,
		);
		$package['sign']=$this->md5_sign($package);
		return $package;
	}
	/*
		统一下单接口
		$params=array(
			'title'=>'商品描述',
			'tid'=>'订单号',
			'fee'=>'订单金额',
			'product_id'=>'产品ID（ NATIVE 时必填）',
		//以下参数为可选参数
			'notify_url'=>'回调地址',
			'appid'=>'公众号或小程序appid',
			'openid'=>'粉丝openid',
		);
	*/
	public function create_order($params,$trade_type){
		$api_url='https://api.mch.weixin.qq.com/pay/unifiedorder';
		$package = array(
			'appid'=>$params['appid']?:$this->config['appid'],
			'mch_id'=>$this->config['mch_id'],
			'nonce_str'=>random(8),
			'body'=>$params['title'],
			'attach'=>$_SESSION['uniacid'],
			'out_trade_no'=>$params['tid'],
			'total_fee'=>round($params['fee']*100),
			'spbill_create_ip'=>CLIENT_IP,
			'time_start'=>date('YmdHis', TIMESTAMP),
			'time_expire'=>date('YmdHis', TIMESTAMP + 600),
			'notify_url'=>$params['notify_url']?:SITEROOT .'custom/payresult/wechat_notify.php',
			'trade_type'=>$trade_type,
		);
		if($trade_type=='NATIVE'){
			$package['product_id']=$params['product_id'];
			$package['spbill_create_ip']=$_SERVER['SERVER_ADDR'];
		}elseif($trade_type=='JSAPI'){
			$package['openid'] =$params['openid']?:$_SESSION['openid'];
		}elseif($trade_type=='MWEB'){
			$package['scene_info'] =ijson_encode(array(
				'h5_info'=>array(
					'type'=>'Wap',
					'wap_url'=>SITEROOT,
					'wap_name'=>$_SESSION['account']['title'],
				),
			));
		}
		//兼容服务商支付
		if($this->config['sub_pay']==1){
			$package['sub_mch_id']=$this->config['sub_mch_id'];
			$package['sub_appid']=$this->config['sub_appid'];
			if($package['openid']){
				$package['sub_openid']=$package['openid'];
				unset($package['openid']);
			}
		}
		return $this->request($api_url,$package);
		exi('支付参数设置错误！','error');
	}
	/*
		付款码支付 
		参数介绍
		$params=array(
			'title'=>'商品描述',
			'tid'=>'订单号',
			'fee'=>'订单金额',
			'auth_code'=>'扫描付款码得到的数据',
		);
		返回值：直接返回来自微信支付服务器的数据（已转为数组，且已过滤错误）
	*/
	public function micro_pay($params){
		if(!$params['auth_code']){
			 exi('请扫描微信付款码','error');
		}
		$api_url='https://api.mch.weixin.qq.com/pay/micropay';
		$package = array(
			'appid'=>$this->config['appid'],
			'mch_id'=>$this->config['mch_id'],
			'nonce_str'=>random(8),
			'body'=>$params['title'],
			'attach'=>$_SESSION['uniacid'],
			'out_trade_no'=>$params['tid'],
			'total_fee'=>round($params['fee']*100),
			'spbill_create_ip'=>$_SERVER['SERVER_ADDR'],
			'time_start'=>date('YmdHis', TIMESTAMP),
			'time_expire'=>date('YmdHis', TIMESTAMP + 600),
			'auth_code'=>$params['auth_code'],
		);
		return $this->request($api_url,$package);
	}
	/*
		企业付款接口
		参数介绍：
		$params=array(
			'mch_billno'=>'商户订单号',
			'openid'=>'收款用户openid',
			'money'=>'支付金额',
			'remark'=>'备注',
		);
		返回值：直接返回来自微信支付服务器的数据（已转为数组，且已过滤错误）
		文档地址
		https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
	*/
	public function mch_pay($params){
		$api_url='https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
		if(is_numeric($params['openid'])){
			$mid=$params['openid'];
			$params['openid']=model('core/account')->get_openid_by_mid($params['openid'],true,$params['wxgid']);
			if(!$params['openid']){
				exi('找不到会员对应的粉丝！','error');
			}
			$from_os=pdo_getcolumn('core_members',array('id'=>$mid,'uniacid'=>$_SESSION['uniacid']),'from_os');
			if(!$params['wxgid'] && $from_os==1){
				$wxgid=pdo_getcolumn('core_fans',array('openid'=>$params['openid'],'mid'=>$mid,'uniacid'=>$_SESSION['uniacid']),'wxgid');
				$wxapp=pdo_get('core_account_wxapp',array('id'=>$wxgid,'uniacid'=>$_SESSION['uniacid']),array('appid','mchid','paykey'));
				$params['appid']=$wxapp['appid'];
				$params['mch_id']=$wxapp['mchid'];
			}
		}
		$params['appid']=$params['appid']?:$this->config['appid'];
		$params['mch_id']=$params['mch_id']?:$this->config['mch_id'];
		$package=array(
			'mch_appid'=>$params['appid'],
			'mchid'=>$params['mch_id'],
			'nonce_str'=>random(32),
			'partner_trade_no'=>$params['mch_billno'],//商户订单号
			'openid'=>$params['openid']?:$_SESSION['openid'],
			'check_name'=>'NO_CHECK',
			'amount'=>round($params['money']*100),
			'desc'=>$params['remark']?:'猜越多得越多，快来抢！',
			'spbill_create_ip'=>$params['spbill_create_ip']?:$_SERVER['SERVER_ADDR'],
		);
		if($params['realname']){
			$package['re_user_name']=$params['realname'];
		}
		$res=$this->request($api_url,$package,true,'',true);
		if($res['result_code']!='SUCCESS'){
			if($res['err_code']=='NO_AUTH'){
				$res=$this->mch_pay3($params);
			}else{
				exi($res['err_code'].':'.$res['err_code_des'],'error');
			}
		}
		return $res;
	}
	/*
		企业转账接口
		参数介绍：
		$params=array(
			'mch_billno'=>'商户订单号',
			'openid'=>'收款用户openid',
			'money'=>'支付金额',
			'remark'=>'备注',
		);
		返回值：直接返回来自微信支付服务器的数据（已转为数组，且已过滤错误）
		文档地址
		https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml
	*/
	public function mch_pay3($params){
		$api_url='https://api.mch.weixin.qq.com/v3/transfer/batches';
		if(is_numeric($params['openid'])){
			$mid=$params['openid'];
			$params['openid']=model('core/account')->get_openid_by_mid($params['openid'],true,$params['wxgid']);
			if(!$params['openid']){
				exi('找不到会员对应的粉丝！','error');
			}
			$from_os=pdo_getcolumn('core_members',array('id'=>$mid,'uniacid'=>$_SESSION['uniacid']),'from_os');
			if(!$params['wxgid'] && $from_os==1){
				$wxgid=pdo_getcolumn('core_fans',array('openid'=>$params['openid'],'mid'=>$mid,'uniacid'=>$_SESSION['uniacid']),'wxgid');
				$wxapp=pdo_get('core_account_wxapp',array('id'=>$wxgid,'uniacid'=>$_SESSION['uniacid']),array('appid','mchid','paykey'));
				$params['appid']=$wxapp['appid'];
				$params['mch_id']=$wxapp['mchid'];
			}
		}
		$params['appid']=$params['appid']?:$this->config['appid'];
		$params['mch_id']=$params['mch_id']?:$this->config['mch_id'];
		$transfer_detail_list=array();
		$transfer_detail_list[0]=array(
			'out_detail_no'=>$params['mch_billno'],
			'transfer_amount'=>round($params['money']*100),
			'transfer_remark'=>$params['remark'],
			'openid'=>$params['openid']?:$_SESSION['openid'],
		);
		if($params['realname']){
			$transfer_detail_list[0]['user_name']=$params['realname'];
		}
		$package=array(
			'appid'=>$params['appid'],
			'out_batch_no'=>$params['mch_billno'],//商户订单号
			'total_num'=>1,
			//'re_user_name'=>'',
			'total_amount'=>round($params['money']*100),
			'batch_name'=>$params['title']?:'企业转账打款',
			'batch_remark'=>$params['remark']?:'企业转账',
			'transfer_detail_list'=>$transfer_detail_list,
		);
		return $this->request($api_url,$package,true,'','',true);
		
	}
	/*
		发放裂变红包
		参数介绍：
		$params=array(
			'mch_billno'=>'商户订单号',
			'openid'=>'收红包用户openid',
			'money'=>'支付金额',
			'remark'=>'备注',
			'send_name'=>'商户名称',
			'total_num'=>'红包总数',
			'wishing'=>'祝福语',
			'act_name'=>'活动名称',
		);
		返回值：直接返回来自微信支付服务器的数据（已转为数组，且已过滤错误）
	*/
	public function grouppack($params){
		$api_url='https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack';
		$package=array(
			'nonce_str'=>random(32),
			'mch_billno'=>$params['mch_billno'],//商户订单号
			'mch_id'=>$this->config['mch_id'],
			'wxappid'=>$this->config['appid'],
			'send_name'=>$params['send_name']?:$_SESSION['account']['title'],
			're_openid'=>$params['openid'],
			'total_amount'=>round($params['money']*100),
			'total_num'=>$params['total_num']?:10,
			'amt_type'=>'ALL_RAND',
			'wishing'=>$params['wishing']?:'恭喜发财，大吉大利！',
			'act_name'=>$params['act_name']?:'发红包啦',
			'remark'=>$params['remark']?:'猜越多得越多，快来抢！',
		);
		//兼容服务商支付
		if($this->config['sub_pay']==1){
			$package['sub_mch_id']=$this->config['sub_mch_id'];
			$package['msgappid']=$this->config['sub_appid'];
			
		}
		return $this->request($api_url,$package,true);
	}
	/*
		发放红包
		参数介绍：
		$params=array(
			'mch_billno'=>'商户订单号',
			'openid'=>'收红包用户openid',
			'money'=>'支付金额',
			'remark'=>'备注',
			'send_name'=>'商户名称',
			'wishing'=>'祝福语',
			'act_name'=>'活动名称',
		);
		返回值：直接返回来自微信支付服务器的数据（已转为数组，且已过滤错误）
	*/
	public function redpack($params){
		$api_url='https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack';
		$fields=array('mch_billno','openid','money');
		foreach($fields as $key){
			if(!$params[$key]){
				return error('关键参数未设置：'.$key);
			}
		}
		if(is_numeric($params['openid'])){		
			$params['openid']=model('core/account')->get_openid_by_mid($params['openid']);
			if(!$params['openid']){
				return error('找不到会员对应的粉丝！');
			}
		}
		$params['send_name']=$params['send_name']?$params['send_name']:$_SESSION['account']['title'];
		$package=array(
			'nonce_str'=>random(32),
			'mch_billno'=>$params['mch_billno'],//商户订单号
			'mch_id'=>$this->config['mch_id'],
			'wxappid'=>$this->config['appid'],
			'send_name'=>$params['send_name']?$params['send_name']:'匿名用户',
			're_openid'=>$params['openid'],
			'total_amount'=>round($params['money']*100),
			'total_num'=>1,
			'wishing'=>$params['wishing']?:'恭喜发财，大吉大利！',
			'client_ip'=>$_SERVER['SERVER_ADDR'],
			'act_name'=>$params['act_name']?:'发红包啦',
			'remark'=>$params['remark']?:'猜越多得越多，快来抢！',
		);
		//兼容服务商支付
		if($this->config['sub_pay']==1){
			$package['sub_mch_id']=$this->config['sub_mch_id'];
			$package['msgappid']=$this->config['sub_appid'];
			
		}
		return $this->request($api_url,$package,true,true);
	}
	/*
		jsapi 申请退款
		https://api.mch.weixin.qq.com/secapi/pay/refund
	*/
	public function refund_pay($params){
		$api_url='https://api.mch.weixin.qq.com/secapi/pay/refund';
		$params['refund_fee']=$params['refund_fee']?:$params['fee'];
		if($params['mid']){
			$from_os=pdo_getcolumn('core_members',array('id'=>$params['mid'],'uniacid'=>$_SESSION['uniacid']),'from_os');
		}
		if(!$params['wxgid'] && $from_os==1){
				$wxgid=pdo_getcolumn('core_fans',array('mid'=>$params['mid'],'uniacid'=>$_SESSION['uniacid']),'wxgid');
				$wxapp=pdo_get('core_account_wxapp',array('id'=>$wxgid,'uniacid'=>$_SESSION['uniacid']),array('appid','mchid','paykey'));
				$params['appid']=$wxapp['appid'];
				$params['mch_id']=$wxapp['mchid'];
		}
		$package = array(
			'appid'=>$params['appid']?:$this->config['appid'],
			'mch_id'=>$params['mch_id']?:$this->config['mch_id'],
			'nonce_str'=>random(8),
			'transaction_id'=>$params['transid'],
			'out_trade_no'=>$params['tid'],
			'out_refund_no'=>$params['refund_no'],
			'total_fee'=>round($params['fee']*100),
			'refund_fee'=>round($params['refund_fee']*100),
			'refund_desc'=>$params['refund_desc'],
			'notify_url'=>$params['notify_url']?:SITEROOT .'custom/payresult/wechat_notify.php',
		);
		//兼容服务商支付
		if($this->config['sub_pay']==1){
			$package['sub_mch_id']=$this->config['sub_mch_id'];
			$package['sub_appid']=$this->config['sub_appid'];
			if($package['openid']){
				$package['sub_openid']=$package['openid'];
				unset($package['openid']);
			}
		}
		return $this->request($api_url,$package,true);
	}
	//V3https://api.mch.weixin.qq.com/v3/certificates
	public function certificates(){
		$api_url='https://api.mch.weixin.qq.com/v3/certificates';
		$package=array('isjy'=>1);
		$res=$this->request($api_url,$package,true,'',true,true);
		$pem=$res['data'][0];
		if($pem['serial_no'] && $pem['serial_no']==$this->config['payserial_no']){
			require ROOT_D.'/core/library/aes/AesGcm.php';
			$AesGcm= new AesGcm();
			$data = $AesGcm->decrypt($pem['encrypt_certificate']['ciphertext'], $this->config['v3key'], $pem['encrypt_certificate']['nonce'], $pem['encrypt_certificate']['associated_data']);
			$cert_file=ROOT_AT."certs/{$_SESSION['uniacid']}/{$this->config['mch_id']}_paypublic_key.pem";
			file_put_contents($cert_file,$data);
			//刷新证书到期时间
			$pay=uni_setting('pay');
			$pay['payexpire_time']=$pem['expire_time'];
			uni_setting('pay',$pay);
		}
		return true;
	}
	//V3https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_5_1.shtml
	public function opendianjin($sub_mchid='',$wechat_dianjin=0){
		$api_url='https://api.mch.weixin.qq.com/v3/goldplan/merchants/changegoldplanstatus';
		$package=array('sub_mchid'=>$sub_mchid,'operation_type'=>$wechat_dianjin?'OPEN':'CLOSE');
		$res=$this->request($api_url,$package,true,'',true,true);
		if($res['code']){
			exi('点击计划开关异常：'.$res['code'].':'.$res['message'],'error');
		}
		return true;
	}
	/*
		发起接口请求
	*/
	private function request($api_url,$package,$ssl=false,$msg='',$isres=false,$isv3=false){
		if($ssl && !$isv3){
			$this->check_cert($msg);
			$extra=array(
				'CURLOPT_SSLCERT'=>$this->config['apiclient_cert'],
				'CURLOPT_SSLKEY'=>$this->config['apiclient_key'],
			);
		}else{
			$extra=array();
		}
		if($isv3){
			$xml=json_encode($package);
			$nonce_str = random(32);//随机串
			$sign=$this->md5_signv3('POST',$api_url,$xml,$nonce_str,$isres);
			if(!$sign && $isres){
				return error('签名为空！');
			}elseif(!$sign){
				exi('签名为空！','error');
			}
			$mch_id=$package['mch_id']?:$this->config['mch_id'];
			$serial_no=$this->config['serial_no'];//商户证书序列号（不是支付证书）；
			$timestamp=$package['timestamp']?:TIMESTAMP;
			$token=sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $mch_id, $nonce_str, $timestamp, $serial_no, $sign);
			$extra=array(
				'Content-Type' => 'application/json',
				'Authorization'=> $token
			);
		}else{
			$package['sign']=$this->md5_sign($package);
			$xml=array2xml($package);
		}
		$res=cfc('http')->ihttp_request($api_url,$xml,$extra);
		if(is_error($res)){
			if($msg){
				return error($res['message']);
			}else{
				exi($res['message'].'，请求异常！','error');
			}
		}
		$res2=$res;
		$res=xml2array($res['content']);
		$res=$res?$res:json_decode($res2['content'],true);
		$res['return_code']=$res['return_code']?$res['return_code']:$res['code'];
		$res['return_msg']=$res['return_msg']?:$res['message'];
		if($res['return_code']!='SUCCESS' && $res['return_code']){
			if($isres){
				return $res;
			}
			if($msg){
				return error($res['return_msg']);
			}else{
				if($isv3){
					$msgbf='请联系客服设置好V3参数！';
				}else{
					$msgbf='请联系客服设置好参数！';
				}
				exi($res['return_code'].':'.$res['return_msg'].','.$msgbf,'error');
			}
		}
		if($res['result_code']!='SUCCESS' && $res['result_code']){
			if($isres){
				return $res;
			}
			if($msg){
				return error($res['err_code']);
			}else{
				exi($res['err_code'].':'.$res['err_code_des'],'error');
			}
		}
		return $res;
	}
	/*
		检查是否上传证书
	*/
	private function check_cert($msg=''){
		if(!is_file($this->config['apiclient_cert']) || !is_file($this->config['apiclient_key'])){
			if($msg){
				return error('请先上传支付证书');
			}else{
				exi('请先上传支付证书！','error');
			}
		}
		return true;
	}
	/*
		生成签名
	*/
	private function md5_sign($package){
		ksort($package);
		$string = '';
		foreach($package as $key => $v) {
			if(empty($v)){
				continue;
			}
			$string .= "{$key}={$v}&";
		}
		$string .= "key={$this->config['key']}";
		return strtoupper(md5($string));
	}
	/*
		V3生成签名
	*/
	private function md5_signv3($http_method = 'POST',$url = '',$body = '',$nonce_str='',$isres=false){
		if(version_compare(PHP_VERSION, '7.2.0') == -1 && !$isres){
			exi('PHP版本必须7.2以上，才能使用微信支付V3版！您当前PHP版本是：'.PHP_VERSION,'error');
		}
		$mch_private_key = $this->getMchKey(true);//私钥
        if(!$mch_private_key){
            exi('私钥获取失败：openssl_get_privatekey获取异常！','error');
        }
        $timestamp = "".TIMESTAMP;//时间戳
        $nonce = $nonce_str?:random(32);//随机串
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        //构造签名串
        $message = $http_method."\n".
            $canonical_url."\n".
            $timestamp."\n".
            $nonce."\n".
            $body."\n";//报文主体
        //计算签名值
        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
		if(!$raw_sign && !$isres){
			exi('V3支付签名异常，openssl_sign函数不正常：请联系管理员排查服务器环境！','error');
		}
        $sign = base64_encode($raw_sign);
		return $sign;
	}
	//私钥
    private function getMchKey($isv3=false){
        //path->商户私钥文件存放路径
        $key=$this->config['apiclient_key'];
        $file = file_get_contents($this->config['apiclient_key']);
        if (!$file) {
            exi('私钥读取有误，证书内容为空：','error');
        }
        return openssl_get_privatekey(file_get_contents($key));
    }
}